<?php
/**
 *
 * @author Gabriel Dodan , gabriel.dodan@gmail.com
 * @copyright Copyright (c) 2012 Gabriel Dodan
 * @license The MIT License http://www.opensource.org/licenses/mit-license.php , see LICENSE.txt file also
 */

class PageBase {
	
	/**
	 * The page's output, all content
	 * @var string
	 */
	public		static $output     			= '';
	
	/**
	 * PagesGroup instance
	 * @var PagesGroup
	 */
	public		static $pageGroupInstance	= NULL;
    
	/**
	 * List of CSS files added into CSS files placeholder 
	 * @var array
	 */
	protected	static $cssFiles   			= array();
	
	/**
	 * List of JS files added into JS files placeholder
	 * @var array
	 */
	protected	static $jsFiles    			= array();
	
	/**
	 * List of CSS files added into CSS batch placeholder
	 * @var array
	 */
	protected	static $cssBatch   			= array();
	
	/**
	 * List of JS files added into JS batch placeholder 
	 * @var array
	 */
	protected	static $jsBatch    			= array();
	
	/**
	 * Placeholders storage. key => val array, key=placeholder name, val=placeholder content
	 * @var array
	 */
	protected   static $placeholders		= array();
	
	final function __construct() {
		Sys::errorHandler("Page instantiation not allowed");
	}
	
	
	static function loadComp($component, $componentParams = array(), $returnContent = FALSE) {
		$arr = explode("->", $component);
		if ( count($arr) == 2 ) {
			// component as object method
			static $instances = array();
			
			$class	= $arr[0];
			$method	= $arr[1];
			$file	= Locator::pathAppDir() . "/components/{$class}/{$class}.php";
			
			if ( !array_key_exists($class, $instances) ) {
				if ( is_file($file) ) {
					require_once $file;
					$instances[$class] =  new $class();
				}
				else {
					Sys::errorHandler("renderComp(), Component '{$component}' not found");
					return NULL;
				}
			}
			
			
			$args = array_values($componentParams);
			
			if ( $returnContent ) {
				ob_start(); ob_implicit_flush(0);
				call_user_func_array(array($instances[$class], $method), $args);
				return ob_get_clean();
			}
			else {
				call_user_func_array(array($instances[$class], $method), $args);
			}
		}
		else {
			// component as script
			static $cachedComps = array();
			$file = Locator::pathAppDir() . "/components/{$component}/{$component}.php";
				
			if ( !in_array($component, $cachedComps) ) {
				if ( is_file($file) ) {
					$cachedComps[] = $component;
				}
				else {
					Sys::errorHandler("renderComp(), Component '{$component}' not found");
					return NULL;
				}
			}
	
			/* add params into component scope */
			foreach ($componentParams AS $key => $val) {
				${
					$key} = $val;
			}
			if ( $returnContent ) {
				ob_start(); ob_implicit_flush(0);
				require($file);
				return ob_get_clean();
			}
			else {
				require($file);
			}
		}
	
	}
	
	/**
	 * Load the page group file and run the page method. 
	 * This method is part of the workflow, it is called by layouts in order to inject the main content , the content generated by action.
	 * @param bool $suppressHooks
	 */
	static function mainContent($suppressHooks=FALSE) {
		if ( !$suppressHooks ) {
			HooksManager::runHookActions(Workflow::HOOK_MAIN_CONTENT_START);
		}
		
		$method = Request::getPageMethod();
		if ( method_exists( Page::$pageGroupInstance,  $method) ) {
			Page::$pageGroupInstance->beforePage();
			Page::$pageGroupInstance->{$method}();
			Page::$pageGroupInstance->afterPage();
		}
		else {
			Sys::errorHandler("Page '" . Request::getPage() . "' not found", true);
		}
		
		if ( !$suppressHooks ) {
			HooksManager::runHookActions(Workflow::HOOK_MAIN_CONTENT_END);
		}
		
	}
	
	/**
	 * Registers a placeholder
	 * @param string $name
	 */
	static function placeholder($name) {
		Page::$placeholders[$name] = '';
		echo '<!-- {placeholder-' . $name . '} -->';
	}
	
	/**
	 * Appends content to a placeholder
	 * @param string $name
	 * @param string $content
	 */
	static function placeholderAppend($name, $content) {
		Page::$placeholders[$name] .= $content; 
	}
	
	/**
	 * Prepends content to a placeholder
	 * @param string $name
	 * @param string $content
	 */
	static function placeholderPrepend($name, $content) {
		Page::$placeholders[$name] = $content . Page::$placeholders[$name];
	}
	
	/**
	 * Sets content for a placeholder
	 * @param string $name
	 * @param string $content
	 */
	static function placeholderSet($name, $content) {
		Page::$placeholders[$name] = $content;
	}
	
	/**
	 * Replace all placeholders with the actual placeholder content, it is called by @see Workflow after all content has been generated.
	 */
	static function replacePlaceholders(){
		
		// set JS batch placeholder
		Page::placeholderSet("__jsbatch__", Page::createTagForBatch('js'));
		
		// set CSS batch placeholder
		Page::placeholderSet("__cssbatch__", Page::createTagForBatch('css'));
		
		
		//echo self::$output ; print_r(self::$placeholders);exit;
		
		$search  = array();
		$replace = array();
		foreach ( Page::$placeholders AS $name => $phContent ) {
			$search[]  = '<!-- {placeholder-' . $name . '} -->';
			$replace[] = $phContent; 
		}
		
		
		//Page::$output = preg_replace($search, $replace, Page::$output, 1);
		Page::$output = str_replace($search, $replace, Page::$output);
	}
	
	/*
	static function placeholder($name) {
		$content = ob_get_clean();
		if ( key_exists($name, Page::$placeholders) ) {
			Page::$placeholders[$name] = array( $content, Page::$placeholders[1] );	
		}
		else {
			Page::$placeholders[$name] = array( $content, '' );
		}
		
		ob_start();
	}
	static function placeholderAppend($name, $content) {
		Page::$placeholders[$name][1] .= $content; 
	}
	static function placeholderPrepend($name, $content) {
		Page::$placeholders[$name][1] = $content . Page::$placeholders[$name][1];
	}
	static function placeholderSet($name, $content) {
		Page::$placeholders[$name][1] = $content;
	}
	static function replacePlaceholders(){
		
		// set JS batch placeholder
		Page::placeholderSet("__jsbatch__", Page::createTagForBatch('js'));
		
		// set CSS batch placeholder
		Page::placeholderSet("__cssbatch__", Page::createTagForBatch('css'));
		
		$placeHoldersContent = '';
		foreach (Page::$placeholders AS $name => $data) {
			$placeHoldersContent .= @$data[0] . @$data[1];
		}
		Page::$output = $placeHoldersContent . Page::$output;
	}
	*/
	
	/**
	 * Placeholder for title
	 */
	static function title() {
		Page::placeholder("__pagetitle__");
	}
	
	/**
	 * Set title placeholder
	 * @param string $value
	 */
	static function setTitle($value) {
		Page::placeholderSet("__pagetitle__", $value);
	}
	
	/**
	 * Placeholder for description
	 */
	static function description() {
		Page::placeholder("__pagederscription__");
	}
	
	/**
	 * Set description placeholder
	 * @param string $value
	 */
	static function setDescription($value) {
		Page::placeholderSet("__pagederscription__", $value);
	}
	
	/**
	 * Placeholder for keywords
	 */
	static function keywords() {
		Page::placeholder("__keywords__");
	}
	
	/**
	 * Set keywords placeholder
	 * @param string $value
	 */
	static function setKeywords($value) {
		Page::placeholderSet("__keywords__", $value);
	}
	
	
	/**
	 * Create either <link> or <script> tag. 
	 * @param string $batch either 'js' (for JS batch) or 'css' (for CSS batch)
	 */
	static protected function createTagForBatch($batch) {
    	$replace = array(
    			"/resources/jquery/ui/"	=>	'{1}',
    			"/resources/jquery/"	=>	'{2}',
    			"/resources/css/"		=>	'{3}',
    			"/resources/js/"		=>	'{4}'
    	);
		
		$urls  = ($batch == 'js' ? Page::$jsBatch : Page::$cssBatch);
		if ( !count($urls) ) {
			return '';
		}
		$files = array(); 
	    foreach ($urls AS $url) {
	    	$files[] = str_replace(Locator::urlHome(), "", $url); 
    	}
    	
    	
    	
		if ( $batch == 'js' ) {
    		$tagUrl = Locator::urlSysDir() . "/batchJS.php?f=" . strtr(implode(",", $files), $replace);
    		return "<script type=\"text/javascript\" src=\"" . $tagUrl . "\"></script>\n";
			
		}
		else if ( $batch == 'css' ) {
    		$tagUrl = Locator::urlSysDir() . "/batchCSS.php?f=" . strtr(implode(",", $files), $replace);
    		return "<link type=\"text/css\" rel=\"stylesheet\" href=\"" . $tagUrl . "\" />\n";
		}
	}
	
	/**
	 * Placeholder for CSS batch
	 */
	static function cssBatch() {
		Page::placeholder("__cssbatch__");
	}
	
	static function cssBatchAdd() {
		$urls	= array();
		$args	= func_get_args();
		foreach ($args AS $arg) {
			if (is_array($arg)) {
				foreach ($arg AS $url) {
					$urls[]	= str_replace(Locator::urlHome(), "", $url);
				}
			}
			else {
				$urls[]	= str_replace(Locator::urlHome(), "", $arg);
			}
		}
    	Page::$cssBatch = array_unique( array_merge(Page::$cssBatch, $urls) );
	}
	
	/**
	 * Placeholder for JS batch
	 */
	static function jsBatch() {
		Page::placeholder("__jsbatch__");
	}
	
	static function jsBatchAdd() {
		$urls	= array();
		$args	= func_get_args();
		foreach ($args AS $arg) {
			if (is_array($arg)) {
				foreach ($arg AS $url) {
					$urls[]	= str_replace(Locator::urlHome(), "", $url);
				}
			}
			else {
				$urls[]	= str_replace(Locator::urlHome(), "", $arg);
			}
		}
    	Page::$jsBatch = array_unique( array_merge(Page::$jsBatch, $urls) );
	}
	
	/**
	 * Placeholder for CSS files
	 */
	static function cssFiles() {
		Page::placeholder("__cssfiles__");
	}
	
	/**
	 * Adds a file into CSS files placeholder
	 * @param string $url CSS file URL
	 * @param array $attrs attrName=>attrVal array with attributes for <link> tag except "type" and "href"  
	 */
	static function cssFilesAdd($url, $attrs=array()) {
    	foreach (Page::$cssFiles AS $f) {
    		if ( $url == $f['url'] ) {
    			return;
    		}
    	}
    	Page::$cssFiles[] = array(
    		'url'	=> $url,
    		'attrs'	=> $attrs
    	);
    	
    	$tag           = "<link";
    	$attrs['type'] = "text/css";
    	$attrs['href'] = $url;
    	$attrs['rel']  = @($attrs['rel'] ? $attrs['rel'] : "stylesheet");
    	foreach ($attrs AS $name => $val) {
    		$tag .= " {$name}=\"{$val}\"";
    	}
    	$tag .= " />";
    	Page::placeholderAppend("__cssfiles__", $tag . "\n");
	}
	
	/**
	 * Placeholder for JS files
	 */
	static function jsFiles() {
		Page::placeholder("__jsfiles__");
	}
	
	/**
	 * Adds a file into JS files placeholder
	 * @param string $url JS file URL
	 * @param array $attrs attrName=>attrVal array with attributes for <script> tag except "type" and "src"
	 */
	static function jsFilesAdd($url, $attrs=array()) {
    	foreach (Page::$jsFiles AS $f) {
    		if ( $url == $f['url'] ) {
    			return;
    		}
    	}
    	Page::$jsFiles[] = array(
    		'url'	=> $url,
    		'attrs'	=> $attrs
    	);
    	
    	
    	$tag           = "<script";
    	$attrs['type'] = "text/javascript";
    	$attrs['src']  = $url;
    	foreach ($attrs AS $name => $val) {
    		$tag .= " {$name}=\"{$val}\"";
    	}
    	$tag .= "></script>";
    	
    	Page::placeholderAppend("__jsfiles__", $tag . "\n");
	}
    
    
}

/* extension mechanism */
$extFile = ltrim(APP_DIR . "/fw-core-extension/Page.php");
if ( is_file($extFile) ) {
	require_once($extFile);
}
if ( !class_exists('Page') ) {
	class Page extends PageBase {
	}
}
?>